from django import forms
from django.forms import ModelForm
from django.template.loader import render_to_string
from django.forms.util import flatatt
from django.forms.widgets import Media
from django.utils.safestring import mark_safe
from django.db import models

from pypsqueak.chrome.widgets import *

class ChromeBreadcrumbForm(forms.Form):
	""" Shows a Breadcrum control on the page.  No post-back/save """
	crumbs = forms.CharField(widget=ChromeBreadcrumbWidget)

	def as_table(self):
		return self.fields['crumbs'].widget.render()

	def append(self,url,title):
		self.fields['crumbs'].widget.append(url,title)

class ChromeModelForm(ModelForm):
	""" Include chrome elements in the standard ModelForm """

	update = mark_safe("""
	<p align=center>
		<button type="submit" alt="Save Form" padding=100px>
			<img src='/files/images/disk.png' alt='Save'/>&nbsp;Save&nbsp;
		</button>
	</p>""")

	insert = mark_safe("""
	<p align=center>
		<button type="submit" alt="Insert" padding=100px>
			<img src='/files/images/disk.png' alt='Save'/>&nbsp;Create New Record&nbsp;
		</button>
	</p>""")

	delete = mark_safe("""	<p align=center>
		<button type='submit' alt='Delete'>
			<img src='/files/images/delete.png' alt='Delete'/>&nbsp;Delete&nbsp;
		</button>
	</p>
	""" )

	## Inline Buttons

	chrome_inline_create = mark_safe("""
	<button type='button' alt='Create' valign=middle>
		<img src='/files/images/add.png' alt='Add' />&nbsp;Create&nbsp;
	</button>
	""" )

	## Inline Images

	chrome_inline_order = mark_safe("""
	<img src="/files/images/order.png" alt="Move Up or Down" class='handle'>
	""" )


	def __init__(self, *args, **kwargs):
		""" Add an automatic prefix with classname and instance pk (if an instance) """

		if not 'prefix' in kwargs:
			if not 'instance' in kwargs:
				kwargs['prefix'] = self.__class__.__name__
			else:
				kwargs['prefix'] = self.__class__.__name__ + '_' + str(kwargs['instance'].pk)

		super(ChromeModelForm, self).__init__(*args, **kwargs)


	def submit(self, type=None):
		""" Return correct submit code for a form """

		if type==None:
			type = self.__class__.__name__

		if not type.find('Update') == -1:
			return self.update
		elif not type.find('Insert') == -1:
			return self.insert
		elif not type.find('Delete') == -1:
			return self.delete
		else:
			return type + ' not found '



	def save(self, commit=True):
		""" If there is an 'delete_me' field, then save on delete """
		if self.cleaned_data.get('delete_me') == True:
			self.instance.delete()
		else:
			return super(ModelForm, self).save(commit)



#	Removed. May need again for subforms that used to inherit from AJAX.
#	class Media:
#		"""	Define the standard media types """
#		js = ('/files/lib/jquery/js/jquery-1.3.2.min.js',
#			'/files/js/AjaxClickable.js',)



class ComboForm(object):
	"""
	Combines a number of complimentary forms
	Add forms via add_forms and add_dependent_forms
	Retrieve forms as ComboFormInstance.FormName
	Allows the addition of multiple forms as a list.
	"""

	def __init__(self):
		self.forms = []
		self.media_forms = []


	def add_dependent_form(self, form, master_object ):
		"""
		Add a form that requires a master object.
		Forms must implement a function called 'set_master' with a single argument.
		"""
		self.add_form(form=form,instances=None)
		self.forms[-1].set_master(master_object)


	def add_form(self, form, instances, request=None ):
		"""
		Add properly instantiated form to self.forms and as self.[formname]
		Passing multiple instances results in self.[formname] having a list
		of instantiated forms.
		"""
		forms = []

		# We depend upon the form automatically and consistently setting prefix as needed.
		#	This behavior is set in the ChromeModelForm class.
		if not issubclass(form, ChromeModelForm):
			raise Exception(form.__name__ + ' is not a subtype of ChromeModelForm')


		if instances == None:
			# No instances because form is a dependent form (insert)
			# Include empty form on page.
			self.forms.append(form())
			setattr(self, form.__name__, self.forms[-1])

		elif isinstance(instances, models.Model):
			# If instances isn't a list, then add a single loaded form

			# Populate from POST if needed.
			if request.method=="POST":
				self.forms.append(form(request.POST, request.FILES, instance=instances))
			else:
				self.forms.append(form(instance=instances ))

			setattr(self, form.__name__, self.forms[-1])

		elif len(instances) == 0:
			# Instances is an empty list

			# We are adding a child form with no set instances. We still need
			# 	the js/media dependencies, in case this form is added inline thru ajax
			self.media_forms.append(form())

		else:
			# Instances is a non-empty list.
			# Add a list of forms instead of a single form.
			iforms = []

			for instance in instances:
				if request.method=="POST":
					iforms.append(form(request.POST, request.FILES, instance=instance))
				else:
					iforms.append(form(instance=instance ))
				self.forms.append(iforms[-1])

			setattr(self, form.__name__, iforms)



	def is_valid(self):
		return all( form.is_valid() for form in self.forms )

	def save(self):
		[form.save() for form in self.forms]

	def submit(self):
		return ChromeModelForm.update

	def as_p(self):
		return mark_safe("".join([f.as_p() for f in self.forms]) )

	def errors(self):
		""" Return a nicely formatted list of errors for included forms """

		s = "<br/><h1>Error List</h1>"

		for f in self.forms:
			if len(f.errors.as_text()) > 0:
				s = s + f.errors.as_ul() + "<br/>"

		if len(s) > 25:
			return mark_safe( s )
		else:
			return ""

	def media(self):
		""" Return the rendered media for all included forms """
		media = Media()

		# Add instantiated form media.
		for form in self.forms:
			[ media.add_js( [js] ) for js in form.media._js ]
			for key, paths in form.media._css.items():
				media.add_css({key:paths})


		# Add form media for inline forms that may added thru ajax.
		for form in self.media_forms:
			[ media.add_js( [js] ) for js in form.media._js ]
			for key, paths in form.media._css.items():
				media.add_css({key:paths})


		return media.render()
